Azure Synapse SQL Pool Resource Monitoring

 

 

Getting resource metadata:

To confirm the TempDB usage on a request level you can leverage the following query:

 

SELECT
sum(pdw.bytes_processed) as 'bytes_written'
,CAST(sum(pdw.bytes_processed)/
1024.0/1024.0/1024.0 AS Decimal(10,1)) AS 'GB_written'
,sum(pdw.rows_processed) as 'rows_written'
,pdw.request_id
from Sys.dm_pdw_dms_workers pdw
WHERE end_time
is not null
AND pdw.type =
'Writer'
AND destination_info like 
'_tempdb%' or destination_info IS NULL
group by pdw.request_id 
HAVING
CAST(sum(pdw.bytes_processed)/1024.0/1024.0/1024.0 AS Decimal(10,1)) > 1

Special thanks to Nick Salch for assisting with the correct metric to track.

If you need to monitor the overall memory usage, you can leverage the following:

 

SELECT
pc1.cntr_value
as Curr_Mem_KB,
pc1.cntr_value/
1024.0 as Curr_Mem_MB,
(pc1.cntr_value/
1048576.0) as Curr_Mem_GB,
pc2.cntr_value
as Max_Mem_KB,
pc2.cntr_value/
1024.0 as Max_Mem_MB,
(pc2.cntr_value/
1048576.0) as Max_Mem_GB,
pc1.cntr_value *
100.0/pc2.cntr_value AS Memory_Utilization_Percentage,
pc1.pdw_node_id
FROM
-- pc1: current memory
sys.dm_pdw_nodes_os_performance_counters
AS pc1
-- pc2: total memory allowed for this SQL instance
JOIN sys.dm_pdw_nodes_os_performance_counters AS pc2
ON pc1.object_name = pc2.object_name AND pc1.pdw_node_id = pc2.pdw_node_id
WHERE
pc1.counter_name =
'Total Server Memory (KB)'
AND pc2.counter_name = 'Target Server Memory (KB)'

 

 

 

 

Whats holding up my query:

If a query is not running from the sys.dm_pdw_exec_requests, to confirm if it is concurrency related or access to a resource.

First confirm that the session is in a suspended status using sys.dm_pdw_exec_requests:

 

Next, using the following wait query to confirm what the session is waiting on:

SELECT waits.session_id,
waits.request_id,
requests.command,
requests.status,
requests.start_time,
waits.type,
waits.state,
waits.object_type,
waits.object_name
FROM sys.dm_pdw_waits waits
JOIN sys.dm_pdw_exec_requests requests
ON waits.request_id=requests.request_id
ORDER BY waits.object_name, waits.object_type, waits.state;

 

If you see the state as queued and wait type as ConcurrencyResourceType that is an indication that you do not have enough concurrency slots to execute the query.

 

 

If there are a few options.

If the session is in a dynamic resource class or workload group, you can increase the DWU to allow for more concurrency slots and concurrent queries.

Please review the following for additional references: Memory and concurrency limits - Azure Synapse Analytics | Microsoft Docs

Workload Group:

Alternatively, to provide more predictable memory and CPU usage. We can leverage Workload Groups.

For example, lets say we need to reduce the overall memory a particular session is using as it seems to be consuming a lot of memory on the overall system.

We can first create a workload group as the below. For this instance, we do not want any aggregate of sessions in this group to use more than 50% of the overall memory CAP_PERCENTAGE_RESOURCE = 50.

In addition, for each request in this Workload Group, the request is granted a minimum of 25% of the overall memory allocated to the Workload group REQUEST_MIN_RESOURCE_GRANT_PERCENT = 25.

In addition, we do not want a request to use more than 25% of the allocated memory to that group REQUEST_MAX_RESOURCE_GRANT_PERCENT = 25.

Its important to note the Effective Values metrics from the following link depending on the DWs allocated: CREATE WORKLOAD GROUP (Transact-SQL) - SQL Server | Microsoft Docs

Because this POC is being conducted on a DW100c, the least amount of resource per request is 25% of the overall resource for that workload group. We will illustrate more below.

Please note that in most cases unless a very important job requires idle resources that no other sessions can use, we will not set the MIN_PERCENTAGE_RESOURCE as that pool of resources cannot be shared.

 

CREATE WORKLOAD GROUP pocsmalltest
WITH
( MIN_PERCENTAGE_RESOURCE =
0
, CAP_PERCENTAGE_RESOURCE =
50
, REQUEST_MIN_RESOURCE_GRANT_PERCENT =
25
, REQUEST_MAX_RESOURCE_GRANT_PERCENT =
25
, IMPORTANCE =
LOW
, QUERY_EXECUTION_TIMEOUT_SEC =
0 )
;

 

 

Next, we will proceed to classify a user to the workload group with the below syntax.

create workload CLASSIFIER pocsmalltestclassifer
WITH (WORKLOAD_GROUP='pocsmalltest',
MEMBERNAME=
'victor1' ,
IMPORTANCE=
NORMAL)

 

 

Finally, we will confirm how much memory is being utilized on the overall system. We will be leveraging the following query: select * from sys.dm_pdw_nodes_resource_governor_resource_pools;

With all sessions idle, we can see the current DWU allocation has a max of around 55GB with the used_memory_kb at 0 for DW100c.

 

However, once a session is executing, we can see that 2.9GB of memory has been allocated to the single session to process its transaction.

 

But what does this mean for concurrent queries?

Remember, DW100c has a max of 4 concurrent queries. Please check the Effective Values link for your respective DWU: CREATE WORKLOAD GROUP (Transact-SQL) - SQL Server | Microsoft Docs

 

As we can see below, we can only execute a max of two concurrent queries with the current caps. 50% of overall resources, with a minimum of 25% per request.

Graphical user interface, application, table

Description automatically generated

 

 

 

Now, to reinforce the concept of Effective Values for the corresponding DWU allocation, lets alter the workload group and reduce the REQUEST_MIN_RESOURCE_GRANT_PERCENT & REQUEST_MAX_RESOURCE_GRANT_PERCENT to try to use even less resources.

ALTER WORKLOAD GROUP pocsmalltest
WITH (REQUEST_MIN_RESOURCE_GRANT_PERCENT = 3,
REQUEST_MAX_RESOURCE_GRANT_PERCENT =
10
)

 

 

As you can see below, we still are allocated the same amount of memory for the request, as the least effective value for DW100c is 25%.

 

Let not forget that concurrent query allowance will be the same as the above as 25% is the minimal resource allocation:

Table

Description automatically generated

 

 

Now, lets alter the REQUEST_MAX_RESOURCE_GRANT_PERCENT to a higher value:

ALTER WORKLOAD GROUP pocsmalltest
WITH (REQUEST_MIN_RESOURCE_GRANT_PERCENT = 50,
REQUEST_MAX_RESOURCE_GRANT_PERCENT =
50
)

 

 

As we can see below, the request is now able to leverage 5.5GB of memory. Nearly doubling the amount of memory allocated to the session. 

 

However, we have essentially reduced the overall number of concurrent transactions by increasing the min and max resource percentage, please see below:

Graphical user interface, application, table

Description automatically generated

 

ALTER WORKLOAD GROUP pocsmalltest
WITH (REQUEST_MIN_RESOURCE_GRANT_PERCENT = 25,
REQUEST_MAX_RESOURCE_GRANT_PERCENT =
50
)

 

 

Even with bringing down the REQUEST_MIN_RESOURCE_GRANT_PERCENT, the concurrency is bounded by the max value in the REQUEST_MAX_RESOURCE_GRANT_PERCENT as we only can process one request, please see below:

Graphical user interface, application, table

Description automatically generated

 

But what resource class or workload classifier is my user using:

 

Remember, sys.dm_pdw_exec_requests will have the info as well.

To cross reference and check the resource class the user is in, you can use the below query. The last column will outline the respective resource class.

 

 

 

WITH perms_cte as
(
select USER_NAME(p.grantee_principal_id) AS principal_name,
dp.principal_id,
dp.type_desc
AS principal_type_desc,
p.class_desc,
OBJECT_NAME(p.major_id)
AS object_name,

 

p.permission_name,
p.state_desc AS permission_state_desc
from sys.database_permissions p
inner JOIN sys.database_principals dp
on p.grantee_principal_id = dp.principal_id
)
SELECT p.principal_name, p.principal_type_desc, p.class_desc, p.[object_name], p.permission_name, p.permission_state_desc, cast(NULL as sysname) as role_name
FROM perms_cte p
WHERE principal_type_desc <> 'DATABASE_ROLE'
UNION
SELECT rm.member_principal_name, rm.principal_type_desc, p.class_desc, p.object_name, p.permission_name, p.permission_state_desc,rm.role_name
FROM perms_cte p
right outer JOIN (
select role_principal_id, dp.type_desc as principal_type_desc, member_principal_id,user_name(member_principal_id) as member_principal_name,user_name(role_principal_id) as role_name--,*
from sys.database_role_members rm
INNER JOIN sys.database_principals dp
ON rm.member_principal_id = dp.principal_id
) rm
ON rm.role_principal_id = p.principal_id
order by principal_name

 

For workload classifier verification, you can use the following:

SELECT cl.classifier_id, cl.name, cl.group_name, cl.importance, det.classifier_type, det.classifier_value, cl.is_enabled, us.altuid, us.gid, us.hasdbaccess, us.islogin, us.isntname, us.isntgroup, us.isntuser, us.issqluser, us.isaliased, us.issqlrole, us.isapprole
FROM sys.workload_management_workload_classifiers cl
INNER JOIN sys.workload_management_workload_classifier_details det
ON cl.classifier_id = det.classifier_id
LEFT JOIN sys.sysusers us
ON det.classifier_type = 'membername' and det.classifier_value = us.name;

 

No SSMS no problem:

Alternatively, in the Azure Portal, you can also monitor your resources.

This includes query activity, which provides metadata of queued queries and active queries. Please note that you can see the pending queries number but not the actual queries, as you can the active queries.

 

You can also use the metrics section of the Azure portal to view various metrics metadata as well.

Graphical user interface, text, application

Description automatically generated

 

Graphical user interface, text, application, email

Description automatically generated

Reference: Monitor your dedicated SQL pool workload using DMVs - Azure Synapse Analytics | Microsoft Docs